package calvin.controller.queue;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;

import calvin.datastore.model.Rate;
import calvin.listener.RateListener;
import calvin.listener.SimpleRateListener;
import calvin.utils.RateCache;
import calvin.utils.RateHelper;

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;

public class RateWatchController extends Controller {

    private static final Logger logger = Logger.getLogger(RateHelper.class
        .getName());

    private static int LOOP_COUNT = 100;
    private static int LOOP_INTERVAL = 3000;

    private List<RateListener> ls = new ArrayList<RateListener>();

    @Override
    public Navigation run() throws Exception {
        this.addListener(new SimpleRateListener());
        int count = 0;
        while (count < LOOP_COUNT) {
            processRate();
            for (RateListener l : ls) {
                l.dealTick();
            }
            Thread.sleep(LOOP_INTERVAL);
            count++;
        }
        Queue queue = QueueFactory.getQueue("rate-watch-queue");
        queue.add(TaskOptions.Builder.withUrl("/queue/rateWatch"));

        return null;
    }

    @Override
    public Navigation handleError(Throwable t) {
        Properties props = new Properties();
        Session session = Session.getDefaultInstance(props, null);

        try {
            Message msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(
                "calvin.helloworld@gmail.com",
                "Admin"));
            msg.addRecipient(Message.RecipientType.TO, new InternetAddress(
                "calvin.helloworld@gmail.com",
                "Calvin"));
            msg.setSubject("["
                + RateHelper.APP_ID
                + "]Error occurred, rate watch queue is terminated abruptly");
            msg.setText(t.getMessage());
            Transport.send(msg);

        } catch (Exception e) {
            logger.log(
                Level.SEVERE,
                "failed to send alert mail to Calvin." + e.getMessage());
        } finally {
            logger.log(
                Level.SEVERE,
                "error occurred, queue is terminated abruptly .."
                    + t.getMessage());
        }

        return null;
    }

    private void processRate() throws Exception {
        String s = RateHelper.get();

        JSONParser parser = new JSONParser();
        JSONObject obj = (JSONObject) parser.parse(s);
        JSONArray array = (JSONArray) obj.get("rate");
        for (Object o : array) {
            JSONObject json = (JSONObject) o;
            Rate rate = new Rate();
            String cp = (String) json.get("currency_pair");
            double bid = Double.valueOf((String) json.get("bid"));
            double ask = Double.valueOf((String) json.get("ask"));
            rate.cp = cp;
            rate.a = ask;
            rate.b = bid;
            rate.t = Long.parseLong((String) json.get("timestamp"));
            RateCache.put(cp, rate);
        }
    }

    public synchronized void addListener(RateListener l) {
        ls.add(l);
    }
}
